package com.kefu.boss.userdetails;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.kefu.boss.mapper.*;
import com.kefu.boss.model.*;
import com.kefu.common.exception.BusinessException;
import com.kefu.framework.config.KefuProperties;
import com.kefu.framework.config.KefuProperties.LoginFailLimit;
import com.kefu.framework.security.KefuUserDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
public class KefuUserDetailsService implements UserDetailsService {
    @Resource
    protected BossRoleMapper bossRoleMapper;
    @Resource
    protected BossUserMapper bossUserMapper;
    @Resource
    protected BossMenuMapper bossMenuMapper;
    @Resource
    protected RedisTemplate<String, BossMenu> redisTemplate;
	@Autowired
	KefuProperties kefu;
	@Resource
    protected BossRoleMenuMapper bossRoleMenuMapper;
	@Resource
    protected BossUserRoleMapper bossUserRoleMapper;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		KefuUserDetails details = findUser(username);
		return details;
	}

    /**
     * 首先检查用户的登录失败次数是否超过阈值，如果超过，则返回一个锁定状态的用户详情对象；
     * 如果没有超过，就查询数据库中的用户信息，将查询到的用户信息封装成KefuUserDetails对象后返回。
     * 如果数据库中没有找到对应的用户信息，则返回null。
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    public KefuUserDetails findUser(String username) throws UsernameNotFoundException {
    	String key=String.format(LoginFailLimit.Redis_Key_Format,username);
    	RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
    	long increment=entityIdCounter.get(); // 获取当前key对应的值（即用户的登录失败次数）
    	if(increment > kefu.getLoginFailLimit().getFailThreshold()) { // 用户的登录失败次数超过了设定的阈值:此时的账户将被锁定
    		KefuUserDetails detail=new KefuUserDetails();
    		detail.setUsername(username);
    		detail.setAccountNonLocked(false);
    		detail.setUserStatus(1);
    		log.warn("账号{}已被锁定",username);
    		return detail;
    		
    	}
        LambdaQueryWrapper<BossUser> wrapper=Wrappers.lambdaQuery();
        wrapper.eq(BossUser::getUserEmail, username);
        List<BossUser> userList = bossUserMapper.selectList(wrapper);
        KefuUserDetails user = null;
        if (userList != null && userList.size() > 0) {
        	BossUser bossUser = userList.get(0);
            user = BeanUtil.toBean(bossUser,KefuUserDetails.class);
            user.setUserId(bossUser.getUserId());
            user.setUsername(bossUser.getUserName());
            user.setUserEmail(bossUser.getUserEmail());
            user.setPassword(bossUser.getUserPwd());
            user.setUserStatus(bossUser.getUserStatus());
            user.setProxyAble(true);
            return user;
        }
        return user;
    }

    public List<BossMenu> findUserMenuById(String userId){
        //用户角色
        List<BossUserRole> userRoleList = bossUserRoleMapper.selectList(Wrappers.lambdaQuery(BossUserRole.class)
                .eq(BossUserRole::getUserId,userId));
        List<String> roleIds = userRoleList.stream().map(BossUserRole::getRoleId).collect(Collectors.toList());
        if (roleIds.isEmpty()) {
            throw BusinessException.msg("未分配角色信息");
        }
        //过滤无效的角色
        List<BossRole> roleList = bossRoleMapper.selectBatchIds(roleIds);
        List<String> roleIdList = roleList.stream()
                .map(role -> role.getRoleId())
                .collect(Collectors.toList());

        // 修剪（或裁剪）存储在指定key的列表。它将只保留列表中指定范围内的元素，其他元素将被删除。start和end参数的含义与range方法相同。例如，trim(key, -1, 0)将删除列表中的所有元素
        List<BossMenu> menuList = Lists.newArrayList();
        //获取角色菜单
        if (!roleIdList.isEmpty()) {
            LambdaQueryWrapper<BossRoleMenu> roleMenuWrapper = Wrappers.lambdaQuery();
            roleMenuWrapper.in(BossRoleMenu::getRoleId, roleIdList);
            //获取当前用户所拥有的所有角色菜单
            List<BossRoleMenu> roleMenuList = bossRoleMenuMapper.selectList(roleMenuWrapper);
            List<String> menuIds = roleMenuList.stream().map(BossRoleMenu::getMenuId)
                    .collect(Collectors.toList());
            // 获取菜单信息
            if(menuIds.size()>0) {
                LambdaQueryWrapper<BossMenu> queryWrapper = Wrappers.lambdaQuery();
                queryWrapper.in(BossMenu::getId, menuIds);
                menuList = bossMenuMapper.selectList(queryWrapper);
                if(menuList.isEmpty()) {
                    throw BusinessException.msg("当前客服没有菜单");
                }
            }else {
                throw BusinessException.msg("当前客服没有菜单");
            }
        }
        return menuList;

    }
}
